/**
 * Created by artheru on 2017/4/1.
 *
 * This is a very fancy API chaining script. Learn it hard!
 */

import randomstring from 'randomstring';

// let randomstring={ todo:
//     generate(){
//         Math.random()*1000000000
//     }
// }

export default {
    invoke: function $N_Invoke(api, params, verbs) {
        return new Promise(function $N_NIP(res, rej){
            let baseVerbs = {
                finish: function $N_NIFinish(pck) {
                    res(pck.result);
                    return "close";
                },
                error: function $N_NIError(pck) {
                    rej(pck.message);
                    return "close";
                },
                todo: function $N_NITodo(pck, ) {
                    return {result:"ok"};
                }
            };
            let allVerbs = typeof verbs==="undefined"?baseVerbs:Object.assign(verbs, baseVerbs);
            let [protocol, path] = api.split("://");
            console.log(`invoke type ${protocol}, path:${path}`);
            let paths = path.split('/');
            if (protocol === "chance") {
                let notify = randomstring.generate();
                events.listen({type: "network", address: notify}, async function $N_NIListen(req, response){
                    let verbHandler = allVerbs[req.body.verb];
                    if (verbHandler)
                        response.json(await verbHandler(req.body));
                });
                events.listen({type: "chance", token: paths[0]}, async function $N_NIChance(send) {
                    send({invoke: paths.slice(1).join("/"), params, notify});
                })
            } else if (protocol === "http") {
                //todo:
            }
        });
    },
    expose: function $N_Expose(...args) {
        let address = randomstring.generate();
        let fun = args[0];
        if (typeof args[0] === "string") {
            address = args[0];
            fun = args[1];
        }
        // return exposed API.
        let api = events.listen({type: "network", address}, async function $N_ExposeListen(req, res){
            let thisCtx = {
                invoker: {
                    res,
                    interact: function $N_ctxInteract(verb, args) {
                        let address=randomstring.generate();
                        let ack = {next: address, verb, args};
                        console.log("thisCtx:",thisCtx);
                        thisCtx.invoker.res.json(ack);
                        return new Promise(function $N_ctxInteractF0(resolve){
                            thisCtx.invoker.res = undefined;
                            if (verb === "finish")
                                resolve();
                            else
                                events.listen({
                                    type: "network",
                                    address
                                }, function $N_Inqres (req, res) {
                                    thisCtx.invoker.res = res;
                                    resolve(req.body);
                                });
                        });
                    },
                }
            };
            try {
                let result = await fun(thisCtx, req.body);
                if (typeof thisCtx.invoker.res !== "undefined")
                    thisCtx.invoker.interact("finish", result);
            } catch (e) {
                console.error("Workflow Error:", e);
                if (thisCtx.invoker.currentResponse)
                    thisCtx.invoker.currentResponse.json({error: e});
            }
        });
        return api;
    }
}